package com.kk.demo.unsface.third;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;

import com.kk.demo.unsface.tools.UnsafeTools;

import sun.misc.Unsafe;
import sun.misc.VM;

/**
 * 通过对DirectByteBuffer的改动，
 * 1，构造函数中去掉释放内存部分
 * 2,自已控制内存的释放
 * 
* 源文件名：UnsafeDirectByteBuffer.java
* 文件版本：1.0.0
* 创建作者：Think
* 创建日期：2016年12月4日
* 修改作者：Think
* 修改日期：2016年12月4日
* 文件描述：TODO
* 版权所有：Copyright 2016 zjhz, Inc. All Rights Reserved.
*/
public class UnsafeDirectByteBuffer {

    private Unsafe unsafe = null;

    public UnsafeDirectByteBuffer() {
        this.unsafe = UnsafeTools.getUnsafe();
    }

    public ByteBuffer getDirectByteBuffer(int cap) {

        try {
            Class dirbuffer;

            dirbuffer = Class.forName("java.nio.DirectByteBuffer");
            ByteBuffer buffer = (ByteBuffer) unsafe.allocateInstance(dirbuffer);

            // 1,设置mark的值
            this.setObjOffsetValue(dirbuffer, "mark", buffer, -1);
            this.setObjOffsetValue(dirbuffer, "capacity", buffer, cap);
            this.setObjOffsetValue(dirbuffer, "limit", buffer, cap);
            this.setObjOffsetValue(dirbuffer, "position", buffer, 0);

            // 针对DirectByteBuffer,进行相关的内存分配
            // 用于判断是否边界对齐
            boolean pa = VM.isDirectMemoryPageAligned();
            // 得到内存页的大小
            int ps = unsafe.pageSize();
            long size = Math.max(1L, (long) cap + (pa ? ps : 0));

            long baseAddress = -1;
            try {
                // 进行内存的分配
                baseAddress = unsafe.allocateMemory(size);
            } catch (OutOfMemoryError x) {
                throw x;
            }
            // 对内存作清零操作
            unsafe.setMemory(baseAddress, size, (byte) 0);

            long address = -1;

            if (pa && (baseAddress % ps != 0)) {
                address = baseAddress + ps - (baseAddress & (ps - 1));
            } else {
                address = baseAddress;
            }

            // 设置原对象中的地址信息
            setObjOffsetValue(dirbuffer, "address", buffer, address);

            return buffer;

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public ByteBuffer getDirectByteBuffer(ByteBuffer db, int mark, int pos, int lim, int cap, int off) {

        try {
            Class dirbuffer = null;

            dirbuffer = Class.forName("java.nio.DirectByteBuffer");

            ByteBuffer buffer = (ByteBuffer) unsafe.allocateInstance(dirbuffer);

            // 1,设置mark的值
            this.setObjOffsetValue(dirbuffer, "mark", buffer, mark);
            this.setObjOffsetValue(dirbuffer, "capacity", buffer, cap);
            this.setObjOffsetValue(dirbuffer, "limit", buffer, lim);
            this.setObjOffsetValue(dirbuffer, "position", buffer, pos);

            long address = -1;

            // 重新生成 地址信息
            // 获取对象的属性信息
            long addressOldValue = this.getObjOffsetValue(dirbuffer, "address", db);

            address = addressOldValue + off;

            // 设置原对象中的地址信息
            setObjOffsetValue(dirbuffer, "address", buffer, address);
            // 得到att对象的偏移
            // 获取到相关的属性
            Field mdrkField = getField(dirbuffer, "att");
            // 找到偏移量
            long offset = unsafe.objectFieldOffset(mdrkField);
            // // 将值设置到属性中
            unsafe.putObject(buffer, offset, db);

            return buffer;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 设置属性的值的信息
    * 方法描述
    * @param name
    * @param value
    * @创建日期 2016年12月4日
    */
    @SuppressWarnings("rawtypes")
    public void setObjOffsetValue(Class dirbuffer, String name, ByteBuffer buffer, long value) {
        // 获取到相关的属性
        Field mdrkField = getField(dirbuffer, name);
        // 找到偏移量
        long offset = unsafe.objectFieldOffset(mdrkField);
        // // 将值设置到属性中
        unsafe.putLong(buffer, offset, value);

    }

    /**
     * 设置属性的值的信息
     * 方法描述
     * @param name
     * @param value
     * @创建日期 2016年12月4日
     */
    public long getObjOffsetValue(Class dirbuffer, String name, ByteBuffer obj) {
        // 获取到相关的属性
        Field mdrkField = getField(dirbuffer, name);
        // 找到偏移量
        long offset = unsafe.objectFieldOffset(mdrkField);
        // // 获取属性值中
        return unsafe.getLong(obj, offset);

    }

    /**
     * 设置属性的值的信息
     * 方法描述
     * @param name
     * @param value
     * @创建日期 2016年12月4日
     */
    public void setObjOffsetValue(Class dirbuffer, String name, ByteBuffer buffer, int value) {
        // 获取到相关的属性
        Field mdrkField = getField(dirbuffer, name);
        // 找到偏移量
        long offset = unsafe.objectFieldOffset(mdrkField);
        // // 将值设置到属性中
        unsafe.putInt(buffer, offset, value);
    }

    /**
     * 得到属性信息
    * 方法描述
    * @param clazz
    * @param fieldName
    * @return
    * @创建日期 2016年12月4日
    */
    private Field getField(Class<?> clazz, String fieldName) {

        // 查找父类中的属性信息
        do {
            try {
                for (Field filed : clazz.getDeclaredFields()) {
                    if (filed.getName().equals(fieldName)) {
                        return filed;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 在父类中继教查找
            clazz = clazz.getSuperclass();
        } while (clazz != null);

        return null;
    }

    /**
     * 进行内存的释放操作
    * 方法描述
    * @创建日期 2016年12月4日
    */
    public void memoryfree(long baseAddress) {
        unsafe.freeMemory(baseAddress);
    }

    // public ByteBuffer slice() {
    // int pos = this.position();
    // int lim = this.limit();
    // assert (pos <= lim);
    // int rem = (pos <= lim ? lim - pos : 0);
    // int off = (pos << 0);
    // assert (off >= 0);
    // return new DirectByteBuffer(this, -1, 0, rem, rem, off);
    // }

    public ByteBuffer slice(ByteBuffer buffer) {
        int pos = buffer.position();
        int lim = buffer.limit();
        int rem = (pos <= lim ? lim - pos : 0);
        int off = (pos << 0);

        return getDirectByteBuffer(buffer, -1, 0, rem, rem, off);
    }

    public static void main(String[] args) {

        int value = 1024300 << 0;
        System.out.println(value);

        UnsafeDirectByteBuffer buffer = new UnsafeDirectByteBuffer();

        System.out.println(buffer);
    }

}
